package com.amt.configure;

import com.amt.exception.InterfaceParamException;
import com.amt.util.AESUtil;
import com.amt.util.RSAUtil;
import com.amt.util.RedisTemplateUtil;
import com.amt.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * @Title: SystemAspect.java 
 * @Package com.amt.configure 
 * @Description: TODO(系统切点配置类) 
 * @author 江伟  
 * @date 2018年11月1日 下午5:10:27 
 * Copyright (c) ©1994-2018 Scjydz.com All Rights Reserved.
 */
@Aspect
@Component
@Slf4j
public class SystemAspect {
	
	@Autowired
	private AESUtil aesUtil;
	@Autowired
	private RSAUtil rsaUtil;
	@Autowired
	private Secret secret;
	@Autowired
	private RedisTemplateUtil redisTemplateUtil;
	
	/**
	 * @description: Controller层切点
	 */
	@Pointcut("@annotation(com.amt.configure.ControllerLog)")
	public void controllerAspect() {
		
	}
	
	/**
	 * @description: 验证参数切点
	 */
	@Pointcut("@annotation(com.amt.configure.CheckSignature)")
	public void checkSignatureAspect() {
		
	}
	 
	/**
	 * @description: 前置通知 用于拦截Controller层记录用户的操作
	 * @param joinPoint
	 */
	@Before(value = "controllerAspect()")
	public void doBefore(JoinPoint joinPoint) {
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();    
		this.save(request, joinPoint, null);
	}
	
	/**
	 * @description: 验证请求参数并解密
	 * @param pjp
	 * @return 解密后的json格式字符串
	 */
	@Around(value = "checkSignatureAspect()")
	public Object checkSignature(ProceedingJoinPoint pjp) throws Throwable {
		// 获取拦截的方法名
		MethodSignature msig = (MethodSignature) pjp.getSignature();
		// 返回被织入增加处理目标对象
		Object target = pjp.getTarget();
		// 为了获取注解信息
		Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
		// 获取注解信息
		CheckSignature annotation = currentMethod.getAnnotation(CheckSignature.class);
		Object[] args = pjp.getArgs();
		log.info("验证参数开始==========");
		if (args.length>0){
			try {
				//解析并设置解密参数内容,如果失败则抛异常
				switch (annotation.signatureType()) {
					case "AES":
						args[0] = aesUtil.aesDecrypt(args[0].toString(), redisTemplateUtil.getAESKey());
						break;
					case "RSA":
						args[0] = rsaUtil.decipher(args[0].toString(), secret.getPrivateKey());
						break;
					default:
						break;
				}
				if (StringUtil.isEmpty(args[0].toString())) throw new InterfaceParamException("非法的参数内容");
				args[0] = args[0].toString().trim().isEmpty() ?"": parseRequestParam(String.valueOf(args[0]));
				log.info("请求参数：{}", args[0]);
				log.info("验证参数结束==========");
			} catch (Exception e) {
				log.error("异常请求方法：{}.{}", target.getClass().getName(),msig.getName());
				log.error("异常请求参数：{}", args[0]);
				log.info("验证参数结束==========");
				throw new InterfaceParamException(e);
			}
		}
		return pjp.proceed(args);
	}
	 

	
	/**
	 * @description: 保存日志内容
	 */
	public void save(HttpServletRequest request, JoinPoint joinPoint, Throwable e) {
        //请求的IP    
        String ip = getIpAddress(request);  
        try {
			// 获取拦截的方法名
			MethodSignature msig = (MethodSignature) joinPoint.getSignature();
			// 返回被织入增加处理目标对象
			Object target = joinPoint.getTarget();
			// 为了获取注解信息
			Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
			// 获取注解信息
			ControllerLog annotation = currentMethod.getAnnotation(ControllerLog.class);
			Object[] args = joinPoint.getArgs();
			if (args.length > 0 ){
				if (StringUtil.isEmpty(args[0].toString())) {
					args[0] = "无";
				} else {
					args[0] = args[0].toString().trim().isEmpty() ?"": parseRequestParam(String.valueOf(args[0]));
				}
				log.info("通知日志开始==========");
				StringBuffer methodSB = new StringBuffer();
				methodSB.append(joinPoint.getTarget().getClass().getName()).append(".").append(joinPoint.getSignature().getName()).append("()");
				log.info("请求方法:{}", methodSB.toString());
				log.info("方法描述:{}", annotation.value());
				log.info("请求参数:{}", args[0]);
				log.info("请求IP:{}", ip);
				log.info("通知日志结束==========");
			}
		} catch (Exception e1) {
			log.error("通知异常信息:{}", e1); 
			log.info("通知日志结束==========");
		}
	}
	
	

	
	/**
	 * @description: 获取用户ip
	 * @param request 请求类
	 * @return ip
	 */
	public static String getIpAddress(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (null == ip || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (null == ip || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (null == ip || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (null == ip || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (null == ip || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}
	
	/**
	 * @description: 请求参数转码处理
	 */
	private String parseRequestParam(String str) {
		StringBuilder encodeStrBuilder = new StringBuilder();
		for (int i = 0, len = str.length(); i < len; i++) {
	       encodeStrBuilder.append(htmlEncode(str.charAt(i)));
	    }
		return encodeStrBuilder.toString();
	}
	
	private static String htmlEncode(char c) {
		switch(c) {
	       case '&':
	           return "&amp;";
			case '<':
				return "&lt;";
			case '>':
				return "&gt;";
	       case '"':
	           return "&quot;";
	       case ' ':
	           return "&nbsp;";
			default:
				return String.valueOf(c);
		}
	}
	
}
